package com.kunpan.admin.service.impl;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import com.kunpan.admin.aop.AutoFillAspect;
import com.kunpan.admin.common.domain.AjaxResult;
import com.kunpan.admin.common.redis.RedisCache;
import com.kunpan.admin.common.satoken.SaTokenUtils;
import com.kunpan.admin.common.utils.RefreshTokenUtils;
import com.kunpan.admin.common.utils.SecurityUtils;
import com.kunpan.admin.common.utils.file.MinioUtils;
import com.kunpan.admin.constant.Constants;
import com.kunpan.admin.constant.HttpStatus;
import com.kunpan.admin.constant.RedisMessage;
import com.kunpan.admin.entity.LoginInfo;
import com.kunpan.admin.entity.RegisterBody;
import com.kunpan.admin.entity.User;
import com.kunpan.admin.mapper.UserMapper;
import com.kunpan.admin.service.UserService;
import org.apache.commons.lang3.ObjectUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private MinioUtils minioUtils;

    @Autowired
    private RedisCache redisCache;


    private static final Logger log = LoggerFactory.getLogger(AutoFillAspect.class);

    @Override
    public AjaxResult login(String email, String password, HttpServletRequest request) {
        User user = userMapper.selectUserInfoByEmail(email);
        if (ObjectUtils.isEmpty(user)) {
            return AjaxResult.warn("此邮箱未注册");
        } else if (!SecurityUtils.matchesPassword(password, user.getPassword())) {
            return AjaxResult.error("密码错误");
        }
        StpUtil.login(user.getUserId());
        StpUtil.getSession().set(Constants.LOGIN_USER, user);
        LoginInfo loginInfo = new LoginInfo();
        BeanUtils.copyProperties(user, loginInfo);
        loginInfo.setTokenValue(StpUtil.getTokenInfo().getTokenValue());
        //生成刷新令牌
        String refreshToken = RefreshTokenUtils.createRefreshToken();
        //生成设备指纹
        String deviceFingerprint = RefreshTokenUtils.buildDeviceFingerprint(request);
        //将使用的空间放入缓存
        String useSpaceKey = String.format(RedisMessage.USER_SPACE_KEY, user.getUserId().toString());
        redisCache.setCacheMapValue(useSpaceKey, user.getUserId().toString(), user.getUseSpace());
        //设置7天过期
        redisCache.expire(useSpaceKey, 7, TimeUnit.DAYS);
        //设置刷新令牌的key;
        //存入redis，过期时间和session有效期一致，当前为7天
//        StpUtil.getSession().set(deviceFingerprint, refreshToken);
        redisCache.setCacheObject(String.format(Constants.REFRESH_TOKRN_KEY, user.getUserId(),
                deviceFingerprint), refreshToken, 7, TimeUnit.DAYS);
        loginInfo.setRefreshToken(refreshToken);
        return AjaxResult.success(loginInfo);
    }

    /**
     * 退出登入
     */
    @Override
    public AjaxResult logout(HttpServletRequest request) {
        Integer userId = Integer.valueOf(StpUtil.getLoginId().toString());
        String deviceFingerprint = RefreshTokenUtils.buildDeviceFingerprint(request);
        StpUtil.logout(userId);
        redisCache.deleteObject(String.format(Constants.REFRESH_TOKRN_KEY, userId,
                deviceFingerprint));
        return AjaxResult.success("退出成功");
    }

    /**
     * 刷新token
     */
    @Override
    public AjaxResult refreshToken(Map<String, String> tokenBody, HttpServletRequest request) {
        String deviceFingerprint = RefreshTokenUtils.buildDeviceFingerprint(request);
        // 2. 获取用户ID
        Integer userId = Integer.valueOf(StpUtil.getLoginIdByToken(StpUtil.getTokenValue()).toString());
        String userRefreshToken = redisCache.getCacheObject(String.format(Constants.REFRESH_TOKRN_KEY, userId,
                deviceFingerprint));
        if (!userRefreshToken.equals(tokenBody.get("refreshToken")) || userRefreshToken.isEmpty()) {
            return AjaxResult.error(HttpStatus.UNAUTHORIZED, "登入过期");
        }
        StpUtil.updateLastActiveToNow();
        //删除旧的token
        redisCache.deleteObject(Constants.SA_TOKEN_AUTHOR + StpUtil.getTokenValue());
        // 4. 生成新 Token
//        StpUtil.logout(userId);
//        new SaLoginModel().setToken(RefreshTokenUtils.createRefreshToken())
        StpUtil.login(userId);
        String newToken = StpUtil.getTokenValue();
        LoginInfo loginInfo = new LoginInfo();
        User user = (User) StpUtil.getSession().get(Constants.LOGIN_USER);
        BeanUtils.copyProperties(user, loginInfo);
        loginInfo.setUseSpace(redisCache.getCacheMapValue(RedisMessage.USER_SPACE_KEY, user.getUserId().toString()));
        loginInfo.setTokenValue(newToken);
        log.info("token续签: {}", newToken);
        return AjaxResult.success("操作成功", loginInfo);
    }

    @Override
    public String register(RegisterBody registerBody) {
        User user = new User();
        BeanUtils.copyProperties(registerBody, user);
        //设置用户状态为 0正常
        user.setStatus(0);
        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
        //设置用户身份为普通用户
        user.setRoles("common");
        user.setUseSpace(0L);
        //默认昵称为邮箱地址
        user.setNickname(user.getEmail());
        //设置默认头像 //TODO 默认头像地址
        user.setAvatar(Constants.DEFAULT_AVATAR);
        //设置初始空间300MB
        user.setTotalSpace(Constants.INITIAL_SPACE);
        if (userMapper.insertUser(user) > 0) {
            return "";
        }
        return "注册失败，请检查网络连接";
    }

    @Override
    public Integer selectUserIdByEmail(String email) {
        return userMapper.selectUserIdByEmail(email);
    }

    @Override
    public AjaxResult selectUserById(Integer userId) {
        User user;
        if (SaTokenUtils.containsKey(Constants.LOGIN_USER)) {
            user = (User) StpUtil.getSession().get(Constants.LOGIN_USER);
            return AjaxResult.success(user);
        } else {
            user = userMapper.selectUserById(userId);
            StpUtil.getSession().set(Constants.LOGIN_USER, user);
            if (user != null) {
                return AjaxResult.success(user);
            } else {
                return AjaxResult.warn("网络异常,请检查网络连接");
            }
        }
    }

    @Override
    public AjaxResult updateUserInfo(User user) {
        int row = userMapper.updateUserInfo(user);
        if (row > 0) {
            try {
                StpUtil.getSession().delete(Constants.LOGIN_USER);
                return AjaxResult.success("修改成功");
            } catch (Exception e) {
                log.error("updateUserInfo方法报错：", e);
                return AjaxResult.error("修改失败，请检查网络连接");
            }

        }
        return AjaxResult.error("修改失败，请检查网络连接");
    }

    /**
     * 修改头像
     */
    @Override
    public AjaxResult updateAvatar(MultipartFile file, String fileMd5) {
        String filePath = minioUtils.minioUpload(file, file.getOriginalFilename(), fileMd5);
        Integer userId = Integer.valueOf(StpUtil.getLoginId().toString());
        if (userMapper.updateUserAvatar(userId, filePath) > 0) {
            ((User) StpUtil.getSession().get(Constants.LOGIN_USER)).setAvatar(filePath);
            Map<String, String> map = new HashMap<>();
            map.put("imgUrl", filePath);
            return AjaxResult.success(map);
        }
        return AjaxResult.error("网络异常");
    }

    /**
     * 修改密码
     */
    @Override
    public int resetUserPwd(Integer userId, String newPassword) {
        return userMapper.updateUserPwd(userId, newPassword);
    }

    /**
     * 获取用户剩余空间
     */
    @Override
    public AjaxResult getFreeSpace() {
        String userId = StpUtil.getLoginId().toString();
        String useSpaceKey = String.format(RedisMessage.USER_SPACE_KEY, userId);
        Long freeSpace = redisCache.getCacheMapValue(useSpaceKey, userId);
        if (freeSpace == null) {
            freeSpace = userMapper.selectUserById(Integer.valueOf(userId)).getUseSpace();
            redisCache.setCacheMapValue(useSpaceKey, userId, freeSpace);
        }
        return AjaxResult.success(freeSpace);
    }

    @Override
    public AjaxResult forgetPassword(String email, String password) {
        String pwd = SecurityUtils.encryptPassword(password);
        if (userMapper.updateUserPwdByEmail(email,pwd) > 0){
            return AjaxResult.success();
        }
            return AjaxResult.error("修改失败");
    }
}
